#include "Sphere.h"
#include "../math/Vector.h"

Sphere::Sphere()
{
}

Sphere::Sphere(float radius, Color3f color)
{
	this->radius = radius;
	this->color = color;
}

Sphere::~Sphere()
{
}

int Sphere::TestHit(Ray3f ray, HitInfo* hit, int& count) {
	Vector3f center = pos;
	Vector3f direction = ray.direction;
	Vector3f point = ray.point;
	
	float dec = direction.Dot(point /* eye */ - center);
	float dd = direction.Dot(direction);
	float ec = (point - center).Dot(point - center);
	float rr = radius*radius;
	float delta = dec*dec - dd*(ec - rr); //delta discriminant
	int solution = 0;
	count = 0;
	if (delta >= 0) {
		float t1 = (-dec - sqrt(delta)) / dd;
		float t2 = (-dec + sqrt(delta)) / dd;
		if (t1 > t2) {
			float t = t1;
			t1 = t2;
			t2 = t;
		}
		
		if (t1 >= EPSILON_HIT) {
			Vector3f nnear(point + direction*t1);
			hit[count].point.Assign(nnear);
			hit[count].normal.Assign((nnear - center).Normalize());
			count++;
		} else {
			printf("1\n");
		}
		if (t2 >= EPSILON_HIT) {
			Vector3f ffar = point + direction*t2;
			hit[count].point = ffar;
			hit[count].normal = (ffar - center).Normalize();
			count++;
		} else {
			printf("2\n");
	    }
	    
		solution = count;
	} else {
		solution = 0;
		count = 0;
	}
	return solution;
}

int Sphere::TestHitGeometry(Ray3f ray, Vector3f* hit, int& count) {
	Vector3f center = pos;
	Vector3f direction = ray.direction.Normalize();
	Vector3f point = ray.point;
	
	float radius2 = radius*radius;
	Vector3f pc = center - point;
	float pc2 = pc.Dot(pc);	
	
	/* init count */
	count = 0;
	
	if (pc2 < radius2) {//inside
		count = 0;
	} else {	
		float pa = pc.Dot(direction);
		if (pa < 0) { //the sphere is behind the ray
			count = 0;
		} else {
			
			float ca2 = pc2 - pa*pa;
			if (ca2 > radius2) {//the ray miss the sphere
				count = 0;
			} else {
				//find the closest
				float ab = sqrt(radius2 - ca2);
				float t1 = pa - ab;
				hit[count++] = point + direction*t1;
				float t2 = pa + ab;
				hit[count++] = point + direction*t2; 
			}
			
			/*float ab2 = radius2 - pc2 + pa*pa;
			if (ab2 > 0) {
				float t = pa - sqrt(ab2);
				hit[count++] = point + direction*t;
			} else {
				count = 0;
			}*/
		}
	}
	return count;
}
